<?php
use frontend\modules\yii2\widgets\layouts\markdown\Markdown;
use frontend\modules\yii2\widgets\layouts\example\Example;
use yii\bootstrap\Button;
use yii\bootstrap\Alert;

$this->title = '基于PHP官方发布的容器安装Yii2.0框架';
$this->registerMetaTag([
    'name' => 'keywords',
    'content' => 'yii,git,docker,Yii2,install,容器,镜像，框架,安装,教程,自定义'
]);
$this->registerMetaTag([
    'name' => 'description',
    'content' => '介绍基于PHP官方推出的最小容器镜像安装Yii框架'
]);
$this->registerMetaTag([
    'name' => 'author',
    'content' => 'chenzhiwei'
]);


$breadcrumb = '基于PHP官方发布的容器安装Yii2.0框架';

$steps = [
    [
        "label" => "准备工作",
        "content" => <<<CODE
## 1. 准备工作
您需要一台安装有Docker的电脑或者服务器，我们建议您在Linux系统下进行本次实验。

### 1.1 安装Docker
Linux系统下请在命令行中执行如下的命令即可完成Docker的安装：
```shell
curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
```

### 1.2 安装docker-compose
`docker-compose`是一个容器管理工具，可以批量管理您的容器组，由于Yii在框架源码中提供的容器服务是通过这个工具实现管理的，因此您也需要安装，如下是安装的命令：
```shell
# 下载文件
sudo curl -L "https://github.com/docker/compose/releases/download/v2.1.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# 设置文件可执行权限
sudo chmod +x /usr/local/bin/docker-compose

# 软连接
sudo link -s /usr/local/bin/docker-compose /usr/bin/docker-compose
```
CODE,
    ],[
        "label" => "制作PHP容器镜像",
        "content" => <<<CODE
## 2. 制作PHP容器镜像
虽然PHP官方已经发布了PHP各种版本的镜像，但都是按照最小系统发布的，也就是说这些镜像中并没有按照我们常用的各种扩展，如：mysqli。因此我们要对它进行二次设计，添加适当的扩展，形成适合我们自己的镜像。
### 2.1 Dockerfile
通过文件`Dockerfile`来设计镜像是常用的方法，这种方式保存了镜像制作过程，有利于镜像的分享和升级维护。

通过如下命令可以下载`Dockerfile`示例：
```shell
git clone -b 8.0.7.1 https://gitee.com/lv_dockerfile/php-fpm.git yii_dockerfile
```
文档结构如下：
```shell
yii_dockerfile
├── Dockerfile
├── nginx.conf
├── startup.sh
└── yii.conf
```
我们来看一下`Dockerfile`文件：
```yaml
#docker build --no-cache -t php-fpm:8.0.7.1 .

FROM php:8.0.7-fpm
MAINTAINER chenzhiwei "chenzhiweiwk@qq.com"

# set timezone
ENV TZ=Asia/Shanghai

# set timezone
RUN ln -snf /usr/share/zoneinfo/\$TZ /etc/localtime && echo \$TZ > /etc/timezone \
    #php config
    && mv "\$PHP_INI_DIR/php.ini-development" "\$PHP_INI_DIR/php.ini" \
    #update the php-ext
    && apt-get update && apt-get install -y \
       libfreetype6-dev \
       libjpeg62-turbo-dev \
       libpng-dev \
       libzip-dev \
       libcurl4-openssl-dev \
       vim \
       git \
    && docker-php-ext-configure gd --with-freetype --with-jpeg \
    && docker-php-ext-install -j$(nproc) gd \
    && docker-php-ext-install zip \
    && docker-php-ext-install pdo_mysql \
    && docker-php-ext-install opcache \
    && docker-php-ext-install mysqli \
    && docker-php-ext-install curl \
    #install nginx
    && apt-get update && apt-get install -y procps wget libpcre3-dev zlib1g-dev openssl libssl-dev \
    && cd /tmp \
    && wget http://nginx.org/download/nginx-1.20.1.tar.gz \
    && tar -zxf nginx-1.20.1.tar.gz \
    && cd nginx-1.20.1 \
    && mkdir -p /var/tmp/nginx/client/ \
    && mkdir -p /var/tmp/nginx/proxy/ \
    && mkdir -p /var/tmp/nginx/fcgi/ \
    && mkdir -p /var/tmp/nginx/scgi/ \
    && mkdir -p /var/tmp/nginx/scgi/ \
    && useradd -s /sbin/nologin -M nginx \
    && ./configure \
         --prefix=/usr/local/ \
         --sbin-path=/usr/sbin/ \
         --conf-path=/usr/local/nginx/nginx.conf \
         --error-log-path=/usr/local/nginx/log/error.log \
         --http-log-path=/usr/local/nginx/log/access.log \
         --pid-path=/var/run/nginx/nginx.pid  \
         --lock-path=/var/lock/nginx.lock \
         --user=nginx \
         --group=nginx \
         --with-http_ssl_module \
         --with-http_flv_module \
         --with-http_stub_status_module \
         --with-http_gzip_static_module \
         --http-client-body-temp-path=/var/tmp/nginx/client/ \
         --http-proxy-temp-path=/var/tmp/nginx/proxy/ \
         --http-fastcgi-temp-path=/var/tmp/nginx/fcgi/ \
         --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi \
         --http-scgi-temp-path=/var/tmp/nginx/scgi \
         --with-pcre \
    && make install \
    && rm /tmp/nginx-1.20.1.tar.gz \
    && rm -rf /tmp/nginx-1.20.1 \ 
    && mkdir /usr/local/nginx/vhosts \ 
    && mkdir /usr/local/nginx/certs 

COPY nginx.conf /usr/local/nginx/nginx.conf
COPY yii.conf /usr/local/nginx/vhosts/yii.conf
COPY startup.sh /srv/startup.sh


# clear the apt list
RUN rm -r /var/lib/apt/lists/* \
  && chmod 777 /srv/startup.sh \
  && cd /var/www/html \
  && git clone -b 2.0.43.1.1 https://gitee.com/lv_frame/yii.git yii \
  && chown www-data:www-data -R yii 

WORKDIR /var/www/html

# start php-fpm and nginx
ENTRYPOINT ["/bin/bash", "-C", "/srv/startup.sh"]
```
上述的文件主要完成了以下的配置：
- 把容器内的时区设置为上海时间（Asia/Shanghai）；
- 安装PHP扩展：mysql,zip,curl,gd；
- 安装git,vim这些常用的软件；
- 安装nginx服务器代理，这样容器就可以独立向外部提供服务；
- `startup.sh`会在容器完成启动后运行，用于启动nginx,php-fpm等服务；

### 2.2 生成镜像
大家可以看`Dockerfile`文件的第一行就是生成镜像的命令：
```shell
cd yii_dockerfile
docker build --no-cache -t php-fpm:8.0.7.1 .
```
通过如下命令可以查看已经生成的镜像：
```shell
lvzmen:yii_dockerfile docker images
REPOSITORY   TAG        IMAGE ID       CREATED       SIZE
php-fpm      8.0.7.1    7322daa6e4ee   6 weeks ago   603MB
```
接下来步骤将介绍如何使用这个镜像。

### 2.3 福利
如果大家因为本地电脑或者网络等原因无法完成镜像的制作，可以直接拉取我们制作好的：
```shell
docker pull lvzmen/php-fpm:8.0.7.1
```
这个镜像的详细信息请看：[hub.docker.com](https://hub.docker.com/r/lvzmen/php-fpm)
CODE
    ],[
        "label" => "下载Yii2.0框架",
        "content" => <<<CODE
## 2. 下载Yii2.0框架
执行下面的命令下载Yii2.0框架：
```shell
git clone -b 2.0.43 https://github.com/yiisoft/yii2-app-advanced.git yii
```
上述命令拉取的框架源码并没有`vendor`目录和相关配置/入口文件，因此您需要对框架进行相关的初始化工作。我们也提供了已经初始化后的框架代码，您可以通过如下命令拉取：
```shell
git clone -b 2.0.43.1.1 https://gitee.com/lv_frame/yii.git yii
```
CODE
    ],[
        "label" => "创建容器组",
        "content" => <<<CODE
## 3. 创建容器组
这里介绍两种方式启动容器，大家各取所需：
- 通过`docker-compose`启动容器；
- 通过`docker run`命令启动容器；

### 3.1 通过`docker-compose`启动容器
如果想用`docker-compose`的方式启动容器，那就需要修改`docker-compose.yml`文件，下面是修改后的`docker-compose.yml`文件：
```yaml
version: '3.2'
services:
  yii:
    image: php-fpm:8.0.7.1
    name: yii2
    ports:
      - 20080:80
    volumes:
      # Mount source-code for development
      - ./:/var/www/html/yii

#  mysql:
#    image: mysql:5.7
#    environment:
#      - MYSQL_ROOT_PASSWORD=verysecret
#      - MYSQL_DATABASE=yii2advanced
#      - MYSQL_USER=yii2advanced
#      - MYSQL_PASSWORD=secret
```
我们用如下的命令来启动容器：
```shell
cd yii
sudo /usr/local/bin/docker-compose up -d
```
如果有如下输入出则表示容器启动成功：
```shell
lvzmen:yii$ sudo docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Image}}"
CONTAINER ID   NAMES      IMAGE
433e4b39d736   yii2  php-fpm:8.0.7.1
```

### 2.2 通过`docker run`启动容器
如果不愿意使用`docker-compose`工具，也可以通过命令行来启动：
```shell
sudo docker run -itd --name yii2 -p 20080:80 -v \$PWD:/var/www/html/yii php-fpm:8.0.7.1
```
查看是否启动成功，请参考上文。
CODE
    ],[
        "label" => "初始化Yii框架",
        "content" => <<<CODE
## 4. 初始化Yii框架
如果您在第2步中拉取的框架代码是`2.0.43.1.1`版本，那说明框架代码已经完成了初始化工作，请跳过本节内容。

如果您拉取的Yii2.0框架源码没有`vendor`依赖包，也没有经过`./init`初始化，则需要进入容器进一步操作：
```shell
lvzmen:Desktop$ docker exec -it yii2 /bin/bash
root@433e4b39d736:/var/www/html# cd yii
```

### 4.1 安装`composer`
此处的`composer`是PHP的依赖包管理工具，由于PHP发布的镜像中并没有，因此需要我们自己下载：
```shell
root@433e4b39d736:/var/www/html/yii# curl -sS https://getcomposer.org/installer | php
```

### 4.1 下载依赖包
在容器内的`/var/www/html/yii`目录下执行如下命令拉取所需依赖包：
```shell
root@433e4b39d736:/var/www/html/yii# php composer.phar update
```

### 4.2 init初始化
拉取完依赖后还是无法运行Yii，因为框架中缺少了入口文件和配置文件，通过在容器内的`/app`目录下执行如下命令即可：
```shell
root@433e4b39d736:/app# ./init
```
CODE
    ],[
        "label" => "完成安装",
        "content" => <<<CODE
## 5. 完成安装
恭喜您，到了这一步说明您已经完成了Yii的安装工作。

### 5.1 通过容器IP访问
想要访问容器内的Yii，需要先获得容器的IP，获取容器IP常用的有两种方法。 

如果您在宿主机，可以执行如下命令获得容器IP：
```shell
lvzmen:Desktop$ docker inspect yii2| grep IPA
            "SecondaryIPAddresses": null,
            "IPAddress": "",
                    "IPAMConfig": {
                    "IPAddress": "172.23.0.4",
```
如果您在容器内部，可以查看`/etc/hosts`文件获得容器IP:
```shell
root@433e4b39d736:/app# cat /etc/hosts
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.23.0.4      898a462156ae
```
容器ID（433e4b39d736）所对应的就是容器的IP，得到容器IP后，我们就可以在浏览器中直接输入IP访问：
![通过容器IP直接访问容器内的Yii前台首页](/images/20211129144959.png "通过容器IP直接访问容器内的Yii前台首页")

### 5.2 通过端口访问
从`docker-compose.yml`文件得知，容器内部的`80`端口映射到了宿主机的`20080`端口，因此您可以通过宿主机的`20080`端口来访问容器的YII，假设`192.168.148.130`是你宿主机的IP，则可以通过如下访问：
![通过宿主机端口访问容器Yii前台首页](/images/20211129145620.png "通过宿主机端口访问容器Yii前台首页")

### 5.3 权限问题
如果您在访问的时候报了如下错误，则表示您的目录权限有问题：
![目录无权限报错](/images/20211130181348.png "目录无权限报错")

解决方法是在容器内部批量修改项目的权限：
```shell
root@433e4b39d736:/var/www/html/yii# chown www-data:www-data -R ../yii
```
如果上述的修改权限的操作失败，就说明您的项目所在的宿主机中目录很特殊，建议放在宿主机的`/srv`目录下后再尝试一下。
CODE
    ]
];

require "template.php";